home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Add-Ons / BBEdit / MacBob 1.0ß2 / Source / Bob / Compiler.cp < prev    next >
Encoding:
Text File  |  1995-12-12  |  31.3 KB  |  1,736 lines  |  [TEXT/KAHL]

  1. /***
  2.   *
  3.   *    Compiler.cp - bytecode compiler
  4.   *
  5.   *    Original code: Copyright (c) 1991, by David Michael Betz.  All rights reserved
  6.   *    Modified by Christopher E. Hyde, 1995
  7.   *
  8.   ***/
  9.  
  10. #include "Bob.h"
  11. #include "Compiler.h"
  12.  
  13.  
  14. #if qDebug
  15. #define    qDebugCompiler        0
  16. #define    qDebugMem        0
  17. #else
  18. #define    qDebugCompiler        0
  19. #define    qDebugMem        0
  20. #endif
  21.  
  22. // BranchHereFrom - fix up a forward reference
  23. #define    BranchHereFrom(i)    _CWordAt(i) = cptr
  24. //#define    BranchHereFrom(i)    FixUp(i)
  25. #define    _PutByte(b)        cbuff[cptr++] = b
  26. #define    _CheckCodeSpace()    { if (cptr >= kMaxCode) NoCodeSpace(); }
  27. #define    _CWordAt(i)        (*(CWord*) &cbuff[i])
  28.  
  29. // Limits
  30. enum {
  31.     kMaxCode    =    kCodeSize - 8,    // allow for some overflow
  32.     kMaxTempMem    =    4 * 1024
  33. };
  34.  
  35. // Variable access function codes
  36. enum { kLoad, kStore, kPush, kDup };
  37.  
  38. // Partial value structure
  39. struct PVal {
  40.     void    (*fFn)(int, int);
  41.     int        fVal;
  42.  
  43.     inline void    Load    (void) const { (*fFn)(kLoad, fVal); }
  44.     inline void    Store    (void) const { (*fFn)(kStore, fVal); }
  45.     inline void    Push    (void) const { (*fFn)(kPush, 0); }
  46.     inline void    Dup        (void) const { (*fFn)(kDup, 0); }
  47.     inline void    ClearFn    (void) { fFn = nil; }
  48. };
  49.  
  50. // Function argument structure
  51. struct TArgument {
  52.     char*        fName;        // argument name
  53.     TArgument*    fNext;        // next argument
  54. };
  55.  
  56. // Literal structure
  57. struct TLiteral {
  58.     TValue        fValue;        // literal value
  59.     TLiteral*    fNext;        // next literal
  60. };
  61.  
  62. typedef TArgument* TArgPtr;
  63. typedef TLiteral* TLitPtr;
  64. typedef int _Code;
  65. typedef int _CWord;
  66. typedef CWord KWord;
  67.  
  68. // Local variables
  69. static TArgPtr        arguments;            // argument list
  70. static TArgPtr        temporaries;        // temporary variable list
  71. static TLitPtr        literals = nil;        // literal list
  72. static TValue        methodclass;        // class of the current method
  73. static CodePtr        cbuff;                // code buffer
  74. static _CWord        cptr;                // code pointer
  75. static Ptr pTempMem = nil, pNextMem = nil;
  76.  
  77. // Break/continue stacks
  78. static KWord bstack[kMaxLoops], *bsp;
  79. static KWord cstack[kMaxLoops], *csp;
  80.  
  81. // External variables
  82. extern TValue    symbols;        // symbol table
  83. extern TValue    classes;        // class table
  84. extern Value    sp;                // stack pointer
  85. #if qDebug
  86. extern KStr    TypeName (int type);
  87. #endif
  88.  
  89. // Forward declarations
  90. static void    DoClass            (void);
  91. static Entry    FindMember        (Class aClass, KStr name);
  92. static Entry    RFindMember        (Class aClass, KStr name);
  93. static void    DoFunction        (KStr name);
  94. static void    DoRegularFunction(KStr name);
  95. static void    DoMemberFunction(Value aClass);
  96. static Vector    DoCode            (KStr name, Value aClass);
  97. static Class    GetClass        (KStr name);
  98. static void    DoStatement        (void);
  99. static void    DoIf            (void);
  100. static KWord*    AddBreak        (int lbl);
  101. static _CWord    RemBreak        (KWord* old, CWord lbl);
  102. static KWord*    AddContinue        (int lbl);
  103. static void    RemContinue        (KWord* old);
  104. static void    DoWhile            (void);
  105. static void    DoDoWhile        (void);
  106. static void    DoFor            (void);
  107. static void    DoBreak            (void);
  108. static void    DoContinue        (void);
  109. static void    DoBlock            (void);
  110. static void    DoReturn        (void);
  111. static void    DoTest            (void);
  112. static void    DoExpr            (void);
  113. static void    RValue            (PVal* pv);
  114. static void    CheckLValue        (PVal* pv);
  115. static void    DoExpr1            (PVal* pv);
  116. static void    DoExpr2            (PVal* pv);
  117. static void    DoAssignment    (PVal* pv, int op);
  118. static void    DoExpr3            (PVal* pv);
  119. static void    DoExpr4            (PVal* pv);
  120. static void    DoExpr5            (PVal* pv);
  121. static void    DoExpr6            (PVal* pv);
  122. static void    DoExpr7            (PVal* pv);
  123. static void    DoExpr8            (PVal* pv);
  124. static void    DoExpr9            (PVal* pv);
  125. static void    DoExpr10        (PVal* pv);
  126. static void    DoExpr11        (PVal* pv);
  127. static void    DoExpr12        (PVal* pv);
  128. static void    DoExpr13        (PVal* pv);
  129. static void    DoExpr14        (PVal* pv);
  130. static void    DoPreincrement    (PVal* pv, int op);
  131. static void    DoPostincrement    (PVal* pv, int op);
  132. static void    DoNew            (PVal* pv);
  133. static void    DoExpr15        (PVal* pv);
  134. static void    DoPrimary        (PVal* pv);
  135. static void    DoCall            (PVal* pv);
  136. static void    DoSend            (KStr selector, PVal* pv);
  137. static void    DoIndex            (PVal* pv);
  138. static int        GetIdList        (TArgPtr& list, KStr term);
  139. static void    AddArgument        (TArgPtr& list, KStr name);
  140. static void    FreeList        (TArgPtr& plist);
  141. static int        FindArg            (KStr name);
  142. static int        FindTemp        (KStr name);
  143. static Entry    FindDataMember    (KStr name);
  144. static int        AddLiteral        (TLitPtr& pval);
  145. static void    FreeLiterals    (TLitPtr& plist);
  146. static void    FRequireId        (TId id = nil);
  147. static void    FRequire        (TToken rtkn);
  148. static void    Require            (TToken tkn, TToken rtkn);
  149. static void    DoLitInteger    (long n);
  150. static void    DoLitString        (void);
  151. static int        MakeLitString    (KStr str);
  152. static int        MakeLitVariable    (Entry sym);
  153. static void    FindVariable    (KStr id, PVal* pv);
  154. static bool    FindClassVar    (Class aClass, KStr name, PVal* pv);
  155. static void    CodeArgument    (int fcn, int n);
  156. static void    CodeTemporary    (int fcn, int n);
  157. static void    CodeMember        (int fcn, int n);
  158. static void    CodeVariable    (int fcn, int n);
  159. static void    CodeIndex        (int fcn, int n);
  160. static void    CodeLiteral        (int n);
  161. static void    PutCByte        (_Code b);
  162. static void    Put2CByte        (_Code a, _Code b);
  163. static _CWord    BranchForward    (_Code op);
  164. static _CWord    PutOpAndWord    (_Code op, CWord w);
  165. static void    FixUp            (_CWord chain);
  166. static char*    copystring        (KStr str);
  167. static void*    GetMemory        (int size);
  168. static void    FreeAll            (void);
  169.  
  170. inline static void CopyIdTo (TId id) { strcpy(id, gTokStr); };
  171. // Free a list of arguments or temporaries
  172. inline static void FreeList (TArgPtr& plist) { plist = nil; }
  173. // Free a list of literals
  174. inline static void FreeLiterals (void) { literals = nil; }
  175. #if !qDebugMem
  176. inline static void FreeAll (void) { pNextMem = pTempMem; }
  177. #endif
  178.  
  179.  
  180. // Initialize the compiler
  181. void
  182. InitCompiler (void)
  183. {
  184.     literals = nil;
  185.     set_nil(&methodclass);
  186.     cbuff = (CodePtr) Calloc(kCodeSize, sizeof(Code));
  187.     pNextMem = pTempMem = (Ptr) Calloc(1, kMaxTempMem);
  188. }
  189.  
  190.  
  191. // Mark compiler variables
  192. void
  193. MarkCompiler (void)
  194. {
  195. //    if (cbuff) {
  196.         for (TLitPtr lit = literals; lit != nil; lit = lit->fNext)
  197.             Mark(&lit->fValue);
  198.         Mark(&methodclass);
  199. //    }
  200. }
  201.  
  202.  
  203. // Compile class or function definitions
  204. void
  205. CompileDefinitions (CIStream& iStream)
  206. {
  207.         // Initialize
  208.     InitScanner(iStream);
  209.     bsp = &bstack[-1];
  210.     csp = &cstack[-1];
  211.  
  212.         // Process statements until end of file
  213.     TToken tkn;
  214.     while ((tkn = Token()) != kEOF) {
  215.         switch (tkn) {
  216.         case kIdentifier:
  217.             TId name;
  218.             CopyIdTo(name);
  219.             DoFunction(name);
  220.             break;
  221.         case kClass:
  222.             DoClass();
  223.             break;
  224.         default:
  225.             ParseError("Expecting a declaration");
  226.             break;
  227.         }
  228.     }
  229. //    EndScanner();
  230. //    EndCompiler();
  231. }
  232.  
  233.  
  234. // Handle class declarations
  235. static void
  236. DoClass (void)
  237. {
  238.     TArgPtr mvars, smvars, fargs;
  239.  
  240.         // Initialize
  241.     mvars = smvars = fargs = nil;
  242.     check(1);
  243.  
  244.         // Get the class name
  245.     TId cname;
  246.     FRequireId(cname);
  247.  
  248.         // Get the optional base class
  249.     TToken tkn;
  250.     TId id;
  251.     if ((tkn = Token()) == ':') {
  252.         FRequireId();
  253.         push_class(GetClass(gTokStr));
  254.         Info("Class ‘%s’, Base class ‘%s’",
  255.                 cname, GetCString(id, sizeof(id), clgetname(sp)));
  256.     } else {
  257.         push_nil();
  258.         SaveToken(tkn);
  259.         Info("Class ‘%s’", cname);
  260.     }
  261.     FRequire('{');
  262.  
  263.         // Create the new class object
  264.     set_class(sp, NewClass(cname, sp));
  265.     AddEntry(&classes, cname, stClass)->fValue = *sp;
  266.  
  267.     // handle each variable declaration
  268.     while ((tkn = Token()) != '}') {
  269.             // check for static members
  270.         TToken type = tkn;
  271.         if (type == kStatic)
  272.             tkn = Token();
  273.  
  274.             // get the first identifier
  275.         if (tkn != kIdentifier)
  276.             ParseError("Expecting a member declaration");
  277.         CopyIdTo(id);
  278.  
  279.             // check for a member function declaration
  280.         if ((tkn = Token()) == '(') {
  281.             GetIdList(fargs, ")");
  282.             FRequire(')');
  283.             AddEntry(clgetfunctions(sp), id,
  284.                      type == kStatic ? stSFunction : stFunction);
  285.             FreeList(fargs);
  286.         } else {        // handle data members
  287.             TArgPtr& table = (type == kStatic ? smvars : mvars);
  288.             AddArgument(table, id);
  289.             if (tkn == ',')
  290.                 GetIdList(table, ";");
  291.             else
  292.                 SaveToken(tkn);
  293.         }
  294.         FRequire(';');
  295.     }
  296.  
  297.         // Store the member variable names
  298.     int i = isnil(clgetbase(sp)) ? 0 : clgetsize(clgetbase(sp));
  299.     for (TArgPtr p = mvars; p != nil; p = p->fNext) {
  300.         Entry entry = AddEntry(clgetmembers(sp), p->fName, stData);
  301.         set_integer(&entry->fValue, i++);
  302.     }
  303.     sp->fClass->cl_size = i;
  304.     FreeList(mvars);
  305.  
  306.         // Store the static member variable names
  307.     for (p = smvars; p != nil; p = p->fNext)
  308.         AddEntry(clgetmembers(sp), p->fName, stSData);
  309.     FreeList(smvars);
  310.     ++sp;
  311.     FreeAll();
  312. }
  313.  
  314.  
  315. // Find a class member
  316. static Entry
  317. FindMember (Class aClass, KStr name)
  318. {
  319.     Entry entry;
  320.  
  321.     if ((entry = FindEntry(&aClass->cl_members, name)) != nil)
  322.         return entry;
  323.     return FindEntry(&aClass->cl_functions, name);
  324. }
  325.  
  326.  
  327. // Recursive FindMember
  328. static Entry
  329. RFindMember (Class aClass, KStr name)
  330. {
  331.     Entry entry;
  332.  
  333.     if ((entry = FindMember(aClass, name)) != nil)
  334.         return entry;
  335.     else if (!isnil(&aClass->cl_base))
  336.         return RFindMember(claddr(&aClass->cl_base), name);
  337.     return nil;
  338. }
  339.  
  340.  
  341. // Handle function declarations
  342. static void
  343. DoFunction (KStr name)
  344. {
  345.     switch (Token()) {
  346.         case '(':
  347.             DoRegularFunction(name);
  348.             break;
  349.         case kCC:
  350.             check(1);
  351.             push_class(GetClass(name));
  352.             DoMemberFunction(sp);
  353.             ++sp;
  354.             break;
  355.         default:
  356.             ParseError("Expecting a function declaration");
  357.             break;
  358.     }
  359. }
  360.  
  361.  
  362. // Parse a regular function definition
  363. static void
  364. DoRegularFunction (KStr name)
  365. {
  366.     // enter the function name
  367.     Info("Function ‘%s’", name);
  368.     check(1);
  369.     push_var(AddEntry(&symbols, name, stSFunction));
  370.  
  371.     // compile the body of the function
  372.     set_bytecode(&sp->fVar->fValue, DoCode(name, &gNil));
  373.     ++sp;
  374.  
  375.     // free the argument and temporary symbol lists
  376.     FreeList(arguments); FreeList(temporaries);
  377.     FreeAll();
  378. }
  379.  
  380.  
  381. // Parse a member function definition
  382. static void
  383. DoMemberFunction (Value aClass)
  384. {
  385.     // get the selector
  386.     TId name, selector;
  387.     FRequireId(selector);
  388.     FRequire('(');
  389.     GetCString(name, sizeof(name), clgetname(aClass));
  390.     Info("Member function ‘%s::%s’", name, selector);
  391.  
  392.     // make sure the type matches the declaration
  393.     Entry entry;
  394.     if ((entry = FindMember(claddr(aClass), selector)) != nil
  395.             && entry->fType != stFunction
  396.             && entry->fType != stSFunction)
  397.         ParseError("Illegal redefinition");
  398.  
  399.     // compile the code
  400.     check(1);
  401.     push_var(AddEntry(clgetfunctions(aClass), selector, stFunction));
  402.     set_bytecode(&sp->fVar->fValue, DoCode(selector, aClass));
  403.     ++sp;
  404.  
  405.     // free the argument and temporary symbol lists
  406.     FreeList(arguments); FreeList(temporaries);
  407.     FreeAll();
  408. }
  409.  
  410.  
  411. // Compile the code part of a function or method
  412. static Vector
  413. DoCode (KStr name, Value aClass)
  414. {
  415.     int tcnt = 0;
  416.  
  417.         // Initialize
  418.     arguments = temporaries = nil;
  419.     cptr = 0;
  420.  
  421.         // Add the implicit 'this' argument for member functions
  422.     if (!isnil(aClass))
  423.         AddArgument(arguments, "this");
  424.     methodclass = *aClass;
  425.     
  426.         // Get the argument list
  427.     GetIdList(arguments, ";)");
  428.  
  429.         // Get temporary variables
  430.     TToken tkn;
  431.     if ((tkn = Token()) == ';') {
  432.         tcnt = GetIdList(temporaries, ")");
  433.         tkn = Token();
  434.     }
  435.     Require(tkn, ')');
  436.     
  437.         // Reserve space for the temporaries
  438.     if (tcnt > 0)
  439.         Put2CByte(opTSPC, tcnt);
  440.  
  441.         // Store the bytecodes, class and function name as the first literals
  442.     TLitPtr lit;
  443.     AddLiteral(lit);                    // will become the bytecode string
  444.     AddLiteral(lit);                    // class
  445.     lit->fValue = *aClass;
  446.     MakeLitString(name);                // function name
  447.  
  448.         // Compile the code
  449.     PutCByte(opPUSH);
  450.     FRequire('{');
  451.     DoBlock();
  452.     PutCByte(opRTS);
  453.  
  454.         // Count the number of literals
  455.     int nlits = 0;
  456.     for (lit = literals; lit != nil; lit = lit->fNext)
  457.         ++nlits;
  458.  
  459.         // Build the function
  460.     check(1);
  461.     push_bytecode(NewVector(nlits));
  462.  
  463.         // Create the code string
  464.     set_string(&literals->fValue, NewString(cptr));
  465.     memcpy(SData(&literals->fValue), cbuff, cptr);
  466.  
  467.         // Copy the literals
  468.     lit = literals;
  469.     for (int i = 0; i < nlits; ++i, lit = lit->fNext)
  470.         VItem(sp, i) = lit->fValue;
  471.  
  472. #if qDebugCompiler
  473.         // Dump the literals
  474.     lit = literals->fNext;
  475.     for (i = 1; i < nlits; ++i, lit = lit->fNext) {
  476.         PrintErrF("%2d: %s -> ", i, TypeName(lit->fValue.fType));
  477.         if (lit->fValue.fType == tString)
  478.             PrintErrF("%X ", lit->fValue.fStr);
  479.         Print(&stderr_iostream, true, &lit->fValue);
  480.         PrintErrF("\r");
  481.     }
  482. //    PrintErrF("\r");
  483. #endif
  484.     FreeLiterals();
  485.  
  486.         // Show the generated code
  487.     if (Opt(DumpCode))
  488.         DumpProcedure(sp);
  489.  
  490.         // Return the code object
  491.     return vecaddr(sp++);
  492. }
  493.  
  494.  
  495. // Get the class associated with a symbol
  496. static Class
  497. GetClass (KStr name)
  498. {
  499.     Entry sym = FindEntry(&classes, name);
  500.  
  501.     if (sym == nil || sym->fValue.fType != tClass)
  502.         ParseError("Expecting a class name");
  503.     return claddr(&sym->fValue);
  504. }
  505.  
  506.  
  507. // Compile a single statement
  508. static void
  509. DoStatement (void)
  510. {
  511.     TToken tkn;
  512.     switch (tkn = Token()) {
  513.         case kIf:            DoIf();                break;
  514.         case kWhile:        DoWhile();            break;
  515.         case kDo:            DoDoWhile();        break;
  516.         case kFor:            DoFor();            break;
  517.         case kBreak:        DoBreak();            break;
  518.         case kContinue:        DoContinue();        break;
  519.         case kReturn:        DoReturn();            break;
  520.         case '{':            DoBlock();            break;
  521.         case ';':                                break;
  522.         default:            SaveToken(tkn);
  523.                             DoExpr();
  524.                             FRequire(';');        break;
  525.     }
  526. }
  527.  
  528.  
  529. // Compile the IF/ELSE expression
  530. static void
  531. DoIf (void)
  532. {
  533.     // compile the test expression
  534.     DoTest();
  535.  
  536.     // skip around the 'then' clause if the expression is false
  537.     _CWord next = BranchForward(opBRF);
  538.  
  539.     // compile the 'then' clause
  540.     DoStatement();
  541.  
  542.     // compile the 'else' clause
  543.     TToken tkn;
  544.     if ((tkn = Token()) == kElse) {
  545.         _CWord end = BranchForward(opBR);
  546.         BranchHereFrom(next);
  547.         DoStatement();
  548.         next = end;
  549.     } else
  550.         SaveToken(tkn);
  551.  
  552.     // handle the end of the statement
  553.     BranchHereFrom(next);
  554. }
  555.  
  556.  
  557. // Add a break level to the stack
  558. static KWord*
  559. AddBreak (int lbl)
  560. {
  561.     KWord* old = bsp;
  562.     if (++bsp < &bstack[kMaxLoops])
  563.         *bsp = lbl;
  564.     else
  565.         ParseError("Too many nested loops");
  566.     return old;
  567. }
  568.  
  569.  
  570. // Remove a break level from the stack
  571. //static _CWord
  572. static int
  573. RemBreak (KWord* old, CWord lbl)
  574. {
  575.    return bsp > old ? *bsp-- : lbl;
  576. }
  577.  
  578.  
  579. // Add a continue level to the stack
  580. static KWord*
  581. AddContinue (int lbl)
  582. {
  583.     KWord* old = csp;
  584.     if (++csp < &cstack[kMaxLoops])
  585.         *csp = lbl;
  586.     else
  587.         ParseError("Too many nested loops");
  588.     return old;
  589. }
  590.  
  591.  
  592. // Remove a continue level from the stack
  593. static void
  594. RemContinue (KWord* old)
  595. {
  596.     csp = old;
  597. }
  598.  
  599.  
  600. // Compile the WHILE expression
  601. static void
  602. DoWhile (void)
  603. {
  604.         // compile the test expression
  605.     _CWord nxt = cptr;
  606.     DoTest();
  607.  
  608.         // skip around the loop body if the expression is false
  609.     _CWord end = BranchForward(opBRF);
  610.  
  611.         // compile the loop body
  612.     KWord* ob = AddBreak(end);
  613.     KWord* oc = AddContinue(nxt);
  614.     DoStatement();
  615.     end = RemBreak(ob, end);
  616.     RemContinue(oc);
  617.  
  618.         // branch back to the start of the loop
  619.     PutOpAndWord(opBR, nxt);
  620.  
  621.         // handle the end of the statement
  622.     FixUp(end);
  623. }
  624.  
  625.  
  626. // Compile the DO/WHILE expression
  627. static void
  628. DoDoWhile (void)
  629. {
  630.     // remember the start of the loop
  631.     _CWord nxt = cptr;
  632.  
  633.     // compile the loop body
  634.     KWord* ob = AddBreak(0);
  635.     KWord* oc = AddContinue(nxt);
  636.     DoStatement();
  637.     CWord end = 0;
  638.     end = RemBreak(ob, end);
  639.     RemContinue(oc);
  640.  
  641.     // compile the test expression
  642.     FRequire(kWhile);
  643.     DoTest();
  644.     FRequire(';');
  645.  
  646.     // branch to the top if the expression is true
  647.     PutOpAndWord(opBRT, nxt);
  648.  
  649.     // handle the end of the statement
  650.     FixUp(end);
  651. }
  652.  
  653.  
  654. // Compile the FOR statement
  655. static void
  656. DoFor (void)
  657. {
  658.     // compile the initialization expression
  659.     FRequire('(');
  660.     TToken tkn;
  661.     if ((tkn = Token()) != ';') {
  662.         SaveToken(tkn);
  663.         DoExpr();
  664.         FRequire(';');
  665.     }
  666.  
  667.     // compile the test expression
  668.     CWord nxt = cptr;
  669.     if ((tkn = Token()) != ';') {
  670.         SaveToken(tkn);
  671.         DoExpr();
  672.         FRequire(';');
  673.     }
  674.  
  675.     // branch to the loop body if the expression is true
  676.     _CWord body = BranchForward(opBRT);
  677.  
  678.     // branch to the end if the expression is false
  679.     _CWord end = BranchForward(opBR);
  680.  
  681.     // compile the update expression
  682.     CWord update = cptr;
  683.     if ((tkn = Token()) != ')') {
  684.         SaveToken(tkn);
  685.         DoExpr();
  686.         FRequire(')');
  687.     }
  688.  
  689.     // branch back to the test code
  690.     PutOpAndWord(opBR, nxt);
  691.  
  692.     // compile the loop body
  693.     FixUp(body);
  694.     KWord* ob = AddBreak(end);
  695.     KWord* oc = AddContinue(update);
  696.     DoStatement();
  697.     end = RemBreak(ob, end);
  698.     RemContinue(oc);
  699.  
  700.     // branch back to the update code
  701.     PutOpAndWord(opBR, update);
  702.  
  703.     // handle the end of the statement
  704.     FixUp(end);
  705. }
  706.  
  707.  
  708. // Compile the BREAK statement
  709. static void
  710. DoBreak (void)
  711. {
  712.     if (bsp < bstack)
  713.         ParseError("Break outside of loop");
  714.     *bsp = PutOpAndWord(opBR, *bsp);
  715. }
  716.  
  717.  
  718. // Compile the CONTINUE statement
  719. static void
  720. DoContinue (void)
  721. {
  722.     if (csp < cstack)
  723.         ParseError("Continue outside of loop");
  724.     PutOpAndWord(opBR, *csp);
  725. }
  726.  
  727.  
  728. // Compile the {} expression
  729. static void
  730. DoBlock (void)
  731. {
  732.     TToken tkn;
  733.     if ((tkn = Token()) != '}') {
  734.         do {
  735.             SaveToken(tkn);
  736.             DoStatement();
  737.         } while ((tkn = Token()) != '}');
  738.     } else
  739.         PutCByte(opNIL);
  740. }
  741.  
  742.  
  743. // Handle the RETURN expression
  744. static void
  745. DoReturn (void)
  746. {
  747.     DoExpr();
  748.     FRequire(';');
  749.     PutCByte(opRTS);
  750. }
  751.  
  752.  
  753. // Compile a test expression
  754. static void
  755. DoTest (void)
  756. {
  757.     FRequire('(');
  758.     DoExpr();
  759.     FRequire(')');
  760. }
  761.  
  762.  
  763. // Parse an expression
  764. static void
  765. DoExpr (void)
  766. {
  767.     PVal pv;
  768.  
  769.     DoExpr1(&pv);
  770.     RValue(&pv);
  771. }
  772.  
  773.  
  774. // Get the rvalue of a partial expression
  775. static void
  776. RValue (PVal* pv)
  777. {
  778.     if (pv->fFn) {
  779.         pv->Load();
  780.         pv->ClearFn();
  781.     }
  782. }
  783.  
  784.  
  785. // Make sure we've got an lvalue
  786. static void
  787. CheckLValue (PVal* pv)
  788. {
  789.     if (pv->fFn == nil)
  790.         ParseError("Expecting an lvalue");
  791. }
  792.  
  793.  
  794. // Handle the ',' operator
  795. static void
  796. DoExpr1 (PVal* pv)
  797. {
  798.     TToken tkn;
  799.     DoExpr2(pv);
  800.     while ((tkn = Token()) == ',') {
  801.         RValue(pv);
  802.         DoExpr1(pv); RValue(pv);
  803.     }
  804.     SaveToken(tkn);
  805. }
  806.  
  807.  
  808. // Handle the assignment operators
  809. static void
  810. DoExpr2 (PVal* pv)
  811. {
  812. #if ((kADDEQ + 9) != kSHREQ)
  813.     #error "kADDEQ + 9 != kSHREQ"
  814. #endif
  815. #if ((opADD + 9) != opSHR)
  816.     #error "opADD + 9 != opSHR"
  817. #endif
  818.  
  819.     DoExpr3(pv);
  820.     while (1) {
  821.         TToken tkn = Token();
  822.         if (tkn == '=') {
  823.             CheckLValue(pv);
  824.             pv->Push();
  825.             PVal rhs;
  826.             DoExpr1(&rhs); RValue(&rhs);
  827.             pv->Store();
  828.         } else if (tkn >= kADDEQ && tkn <= kSHLEQ) {
  829.             CheckLValue(pv);
  830.             DoAssignment(pv, tkn - kADDEQ + opADD);
  831.         } else {
  832.             SaveToken(tkn);
  833.             break;
  834.         }
  835.         pv->ClearFn();
  836.     }
  837. }
  838.  
  839.  
  840. // Handle assignment operations
  841. static void
  842. DoAssignment (PVal* pv, int op)
  843. {
  844.     pv->Dup();
  845.     pv->Load();
  846.     PutCByte(opPUSH);
  847.  
  848.     PVal rhs;
  849.     DoExpr1(&rhs); RValue(&rhs);
  850.     PutCByte(op);
  851.     pv->Store();
  852. }
  853.  
  854.  
  855. // Handle the '?:' operator
  856. static void
  857. DoExpr3 (PVal* pv)
  858. {
  859.     TToken tkn;
  860.     DoExpr4(pv);
  861.     while ((tkn = Token()) == '?') {
  862.         RValue(pv);
  863.         _CWord nxt = BranchForward(opBRF);
  864.         DoExpr1(pv); RValue(pv);
  865.         FRequire(':');
  866.         _CWord end = BranchForward(opBR);
  867.         FixUp(nxt);
  868.         DoExpr1(pv); RValue(pv);
  869.         FixUp(end);
  870.     }
  871.     SaveToken(tkn);
  872. }
  873.  
  874.  
  875. // Handle the '||' operator
  876. static void
  877. DoExpr4 (PVal* pv)
  878. {
  879.     TToken tkn;
  880.     _CWord end = 0;
  881.     DoExpr5(pv);
  882.     while ((tkn = Token()) == kOR) {
  883.         RValue(pv);
  884.         end = PutOpAndWord(opBRT, end);
  885.         DoExpr5(pv); RValue(pv);
  886.     }
  887.     FixUp(end);
  888.     SaveToken(tkn);
  889. }
  890.  
  891.  
  892. // Handle the '&&' operator
  893. static void
  894. DoExpr5 (PVal* pv)
  895. {
  896.     TToken tkn;
  897.     _CWord end = 0;
  898.     DoExpr6(pv);
  899.     while ((tkn = Token()) == kAND) {
  900.         RValue(pv);
  901.         end = PutOpAndWord(opBRF, end);
  902.         DoExpr6(pv); RValue(pv);
  903.     }
  904.     FixUp(end);
  905.     SaveToken(tkn);
  906. }
  907.  
  908.  
  909. // Handle the '|' operator
  910. static void
  911. DoExpr6 (PVal* pv)
  912. {
  913.     TToken tkn;
  914.     DoExpr7(pv);
  915.     while ((tkn = Token()) == '|') {
  916.         RValue(pv);
  917.         PutCByte(opPUSH);
  918.         DoExpr7(pv); RValue(pv);
  919.         PutCByte(opBOR);
  920.     }
  921.     SaveToken(tkn);
  922. }
  923.  
  924.  
  925. // Handle the '^' operator
  926. static void
  927. DoExpr7 (PVal* pv)
  928. {
  929.     TToken tkn;
  930.     DoExpr8(pv);
  931.     while ((tkn = Token()) == '^') {
  932.         RValue(pv);
  933.         PutCByte(opPUSH);
  934.         DoExpr8(pv); RValue(pv);
  935.         PutCByte(opXOR);
  936.     }
  937.     SaveToken(tkn);
  938. }
  939.  
  940.  
  941. // Handle the '&' operator
  942. static void
  943. DoExpr8 (PVal* pv)
  944. {
  945.     TToken tkn;
  946.     DoExpr9(pv);
  947.     while ((tkn = Token()) == '&') {
  948.         RValue(pv);
  949.         PutCByte(opPUSH);
  950.         DoExpr9(pv); RValue(pv);
  951.         PutCByte(opBAND);
  952.     }
  953.     SaveToken(tkn);
  954. }
  955.  
  956.  
  957. // Handle the '==' and '!=' operators
  958. static void
  959. DoExpr9 (PVal* pv)
  960. {
  961. #if 1
  962.     DoExpr10(pv);
  963.     while (1) {
  964.         TToken tkn = Token();
  965.         _Code op;
  966.         if (tkn == kEQ)
  967.             op = opEQ;
  968.         else if (tkn == kNE)
  969.             op = opNE;
  970.         else {
  971.             SaveToken(tkn);
  972.             break;
  973.         }
  974.         RValue(pv);
  975.         PutCByte(opPUSH);
  976.         DoExpr10(pv); RValue(pv);
  977.         PutCByte(op);
  978.     }
  979. #else
  980.     DoExpr10(pv);
  981.     while (1) {
  982.         TToken tkn = Token();
  983.         _Code op;
  984.         switch (tkn) {
  985.             case kEQ:    op = opEQ;        break;
  986.             case kNE:    op = opNE;        break;
  987.             default:    SaveToken(tkn);    return;
  988.         }
  989.         RValue(pv);
  990.         PutCByte(opPUSH);
  991.         DoExpr10(pv); RValue(pv);
  992.         PutCByte(op);
  993.     }
  994. #endif
  995. }
  996.  
  997.  
  998. // Handle the '<', '<=', '>=' and '>' operators
  999. static void
  1000. DoExpr10 (PVal* pv)
  1001. {
  1002.     DoExpr11(pv);
  1003.     while (1) {
  1004.         TToken tkn = Token();
  1005.         _Code op;
  1006.         switch (tkn) {
  1007.             case '<':    op = opLT;        break;
  1008.             case kLE:    op = opLE;        break;
  1009.             case kGE:    op = opGE;        break;
  1010.             case '>':    op = opGT;        break;
  1011.             default:    SaveToken(tkn);    return;
  1012.         }
  1013.         RValue(pv);
  1014.         PutCByte(opPUSH);
  1015.         DoExpr11(pv); RValue(pv);
  1016.         PutCByte(op);
  1017.     }
  1018. }
  1019.  
  1020.  
  1021. // Handle the '<<' and '>>' operators
  1022. static void
  1023. DoExpr11 (PVal* pv)
  1024. {
  1025.     DoExpr12(pv);
  1026.     while (1) {
  1027.         TToken tkn = Token();
  1028.         _Code op;
  1029.         if (tkn == kSHL)
  1030.             op = opSHL;
  1031.         else if (tkn == kSHR)
  1032.             op = opSHR;
  1033.         else {
  1034.             SaveToken(tkn);
  1035.             break;
  1036.         }
  1037.         RValue(pv);
  1038.         PutCByte(opPUSH);
  1039.         DoExpr12(pv); RValue(pv);
  1040.         PutCByte(op);
  1041.     }
  1042. }
  1043.  
  1044.  
  1045. // Handle the '+' and '-' operators
  1046. static void
  1047. DoExpr12 (PVal* pv)
  1048. {
  1049.     DoExpr13(pv);
  1050.     while (1) {
  1051.         TToken tkn = Token();
  1052.         _Code op;
  1053.         if (tkn == '+')
  1054.             op = opADD;
  1055.         else if (tkn == '-')
  1056.             op = opSUB;
  1057.         else {
  1058.             SaveToken(tkn);
  1059.             break;
  1060.         }
  1061.         RValue(pv);
  1062.         PutCByte(opPUSH);
  1063.         DoExpr13(pv); RValue(pv);
  1064.         PutCByte(op);
  1065.     }
  1066. }
  1067.  
  1068.  
  1069. // Handle the '*', '/' and '%' operators
  1070. static void
  1071. DoExpr13 (PVal* pv)
  1072. {
  1073.     DoExpr14(pv);
  1074.     while (1) {
  1075.         TToken tkn = Token();
  1076.         _Code op;
  1077.         switch (tkn) {
  1078.             case '*':    op = opMUL;        break;
  1079.             case '/':    op = opDIV;        break;
  1080.             case '%':    op = opREM;        break;
  1081.             default:    SaveToken(tkn);    return;
  1082.         }
  1083.         RValue(pv);
  1084.         PutCByte(opPUSH);
  1085.         DoExpr14(pv); RValue(pv);
  1086.         PutCByte(op);
  1087.     }
  1088. }
  1089.  
  1090.  
  1091. // Handle unary operators
  1092. static void
  1093. DoExpr14 (PVal* pv)
  1094. {
  1095.     TToken tkn;
  1096.     switch (tkn = Token()) {
  1097.     case '-':
  1098.         DoExpr15(pv); RValue(pv);
  1099.         PutCByte(opNEG);
  1100.         break;
  1101.     case '!':
  1102.         DoExpr15(pv); RValue(pv);
  1103.         PutCByte(opNOT);
  1104.         break;
  1105.     case '~':
  1106.         DoExpr15(pv); RValue(pv);
  1107.         PutCByte(opBNOT);
  1108.         break;
  1109.     case kINC:
  1110.         DoPreincrement(pv, opINC);
  1111.         break;
  1112.     case kDEC:
  1113.         DoPreincrement(pv, opDEC);
  1114.         break;
  1115.     case kNew:
  1116.         DoNew(pv);
  1117.         break;
  1118.     default:
  1119.         SaveToken(tkn);
  1120.         DoExpr15(pv);
  1121.         return;
  1122.     }
  1123. }
  1124.  
  1125.  
  1126. // Handle prefix '++' and '--'
  1127. static void
  1128. DoPreincrement (PVal* pv, int op)
  1129. {
  1130.     DoExpr15(pv);
  1131.     CheckLValue(pv);
  1132.     pv->Dup();
  1133.     pv->Load();
  1134.     PutCByte(op);
  1135.     pv->Store();
  1136.     pv->ClearFn();
  1137. }
  1138.  
  1139.  
  1140. // Handle postfix '++' and '--'
  1141. static void
  1142. DoPostincrement (PVal* pv, int op)
  1143. {
  1144.     CheckLValue(pv);
  1145.     pv->Dup();
  1146.     pv->Load();
  1147.     PutCByte(op);
  1148.     pv->Store();
  1149.     PutCByte(op == opINC ? opDEC : opINC);
  1150.     pv->ClearFn();
  1151. }
  1152.  
  1153.  
  1154. // Handle the 'new' operator
  1155. static void
  1156. DoNew (PVal* pv)
  1157. {
  1158.     TId selector;
  1159.     FRequireId(selector);
  1160.     Class aClass = GetClass(selector);
  1161.  
  1162.     TLitPtr lit;
  1163.     CodeLiteral(AddLiteral(lit));
  1164.     set_class(&lit->fValue, aClass);
  1165.  
  1166.     PutCByte(opNEW);
  1167.     pv->ClearFn();
  1168.     
  1169.     DoSend(selector, pv);
  1170. }
  1171.  
  1172.  
  1173. // Handle function calls
  1174. static void
  1175. DoExpr15 (PVal* pv)
  1176. {
  1177.     DoPrimary(pv);
  1178.     while (1) {
  1179.         TToken tkn = Token();
  1180.         switch (tkn) {
  1181.         case '(':
  1182.             DoCall(pv);
  1183.             break;
  1184.         case '[':
  1185.             DoIndex(pv);
  1186.             break;
  1187.         case kMemRef:
  1188.             TId selector;
  1189.             FRequireId(selector);
  1190.             DoSend(selector, pv);
  1191.             break;
  1192.         case kINC:
  1193.             DoPostincrement(pv, opINC);
  1194.             break;
  1195.         case kDEC:
  1196.             DoPostincrement(pv, opDEC);
  1197.             break;
  1198.         default:
  1199.             SaveToken(tkn);
  1200.             return;
  1201.         }
  1202.     }
  1203. }
  1204.  
  1205.  
  1206. // Parse a primary expression and unary operators
  1207. static void
  1208. DoPrimary (PVal* pv)
  1209. {
  1210.     TId        id;
  1211.     Entry    entry;
  1212.     Class    aClass;
  1213.     TToken    tkn;
  1214.  
  1215.     switch (Token()) {
  1216.     case '(':
  1217.         DoExpr1(pv);
  1218.         FRequire(')');
  1219.         break;
  1220.     case kNumber:
  1221.         DoLitInteger((long) gTokVal);
  1222.         pv->ClearFn();
  1223.         break;
  1224.     case kString:
  1225.         DoLitString();
  1226.         pv->ClearFn();
  1227.         break;
  1228.     case kNil:
  1229.         PutCByte(opNIL);
  1230.         pv->ClearFn();
  1231.         break;
  1232.     case kIdentifier:
  1233.         CopyIdTo(id);
  1234.         if ((tkn = Token()) == kCC) {
  1235.             aClass = GetClass(id);
  1236.             FRequireId();
  1237.             if (!FindClassVar(aClass, gTokStr, pv))
  1238.                 ParseError("Not a class member");
  1239.         }
  1240.         else {
  1241.             SaveToken(tkn);
  1242.             FindVariable(id, pv);
  1243.         }
  1244.         break;
  1245.     default:
  1246.         ParseError("Expecting a primary expression");
  1247.         break;
  1248.     }
  1249. }
  1250.  
  1251.  
  1252. // Compile a function call
  1253. static void
  1254. DoCall (PVal* pv)
  1255. {
  1256.     TToken tkn;
  1257.     int n = 0;
  1258.     
  1259.     // get the value of the function
  1260.     RValue(pv);
  1261.  
  1262.     // compile each argument expression
  1263.     if ((tkn = Token()) != ')') {
  1264.         SaveToken(tkn);
  1265.         do {
  1266.             PutCByte(opPUSH);
  1267.             DoExpr2(pv); RValue(pv);
  1268.             ++n;
  1269.         } while ((tkn = Token()) == ',');
  1270.     }
  1271.     Require(tkn, ')');
  1272.     Put2CByte(opCALL, n);
  1273.  
  1274.     // we've got an rvalue now
  1275.     pv->ClearFn();
  1276. }
  1277.  
  1278.  
  1279. // Compile a message sending expression
  1280. static void
  1281. DoSend (KStr selector, PVal* pv)
  1282. {
  1283.     // get the receiver value
  1284.     RValue(pv);
  1285.  
  1286.     // generate code to push the selector
  1287.     PutCByte(opPUSH);
  1288. #if 0
  1289.     TLitPtr lit;
  1290.     CodeLiteral(AddLiteral(lit));
  1291.     set_string(&lit->fValue, MakeString(selector));
  1292. #else
  1293.     CodeLiteral(MakeLitString(selector));
  1294. #endif
  1295.  
  1296.     // compile the argument list
  1297.     TToken tkn;
  1298.     int n = 1;
  1299.     FRequire('(');
  1300.     if ((tkn = Token()) != ')') {
  1301.         SaveToken(tkn);
  1302.         do {
  1303.             PutCByte(opPUSH);
  1304.             DoExpr2(pv); RValue(pv);
  1305.             ++n;
  1306.         } while ((tkn = Token()) == ',');
  1307.     }
  1308.     Require(tkn, ')');
  1309.  
  1310.     // send the message
  1311.     Put2CByte(opSEND, n);
  1312.  
  1313.     // we've got an rvalue now
  1314.     pv->ClearFn();
  1315. }
  1316.  
  1317.  
  1318. // Compile an indexing operation
  1319. static void
  1320. DoIndex (PVal* pv)
  1321. {
  1322.     RValue(pv);
  1323.     PutCByte(opPUSH);
  1324.     DoExpr();
  1325.     FRequire(']');
  1326.     pv->fFn = CodeIndex;
  1327. }
  1328.  
  1329.  
  1330. // Get a comma separated list of identifiers
  1331. static int
  1332. GetIdList (TArgPtr& list, KStr term)
  1333. {
  1334.     int count = 0;
  1335.     TToken tkn = Token();
  1336.     if (!strchr(term, tkn)) {
  1337.         SaveToken(tkn);
  1338.         do {
  1339.             FRequireId();
  1340.             AddArgument(list, gTokStr);
  1341.             ++count;
  1342.         } while ((tkn = Token()) == ',');
  1343.     }
  1344.     SaveToken(tkn);
  1345.     return count;
  1346. }
  1347.  
  1348.  
  1349. // Add a formal argument
  1350. static void
  1351. AddArgument (TArgPtr& list, KStr name)
  1352. {
  1353.     TArgPtr arg = (TArgPtr) GetMemory(sizeof(TArgument));
  1354.     arg->fName = copystring(name);
  1355.     arg->fNext = list;
  1356.     list = arg;
  1357. }
  1358.  
  1359.  
  1360. // Find an argument offset
  1361. static int
  1362. FindArg (KStr name)
  1363. {
  1364.     TArgPtr arg = arguments;
  1365.  
  1366.     for (int n = 0; arg; n++, arg = arg->fNext)
  1367.         if (strcmp(name, arg->fName) == 0)
  1368.             return n;
  1369.     return -1;
  1370. }
  1371.  
  1372.  
  1373. // Find a temporary variable offset
  1374. static int
  1375. FindTemp (KStr name)
  1376. {
  1377.     TArgPtr tmp = temporaries;
  1378.  
  1379.     for (int n = 0; tmp; n++, tmp = tmp->fNext)
  1380.         if (strcmp(name, tmp->fName) == 0)
  1381.             return n;
  1382.     return -1;
  1383. }
  1384.  
  1385.  
  1386. #if 0
  1387. // Find a class data member
  1388. static Entry
  1389. FindDataMember (KStr name)
  1390. {
  1391.     Entry    entry;
  1392.     Value    aClass;
  1393.  
  1394.     if (!isnil(&methodclass)) {
  1395.         aClass = &methodclass;
  1396.         do {
  1397.             if ((entry = FindEntry(clgetmembers(aClass), name)) != nil)
  1398.                 return entry;
  1399.             aClass = clgetbase(aClass);
  1400.         } while (!isnil(aClass));
  1401.     }
  1402.     return nil;
  1403. }
  1404. #endif
  1405.  
  1406.  
  1407. // Add a literal
  1408. static int
  1409. AddLiteral (TLitPtr& pval)
  1410. {
  1411.     int n = 0;
  1412.     for (TLitPtr* plit = &literals; *plit != nil; plit = &(*plit)->fNext)
  1413.         ++n;
  1414.     TLitPtr lit = (TLitPtr) GetMemory(sizeof(TLiteral));
  1415.     set_nil(&lit->fValue);
  1416.     lit->fNext = nil;
  1417.     pval = *plit = lit;
  1418.     return n;
  1419. }
  1420.  
  1421.  
  1422. // Fetch a token and require it to be an id
  1423. static void
  1424. FRequireId (TId id)
  1425. {
  1426.     Require(Token(), kIdentifier);
  1427.     if (id)
  1428.         CopyIdTo(id);
  1429. }
  1430.  
  1431.  
  1432. // Fetch a token and check it
  1433. static void
  1434. FRequire (TToken rtkn)
  1435. {
  1436.     Require(Token(), rtkn);
  1437. }
  1438.  
  1439.  
  1440. // Check for a required token
  1441. static void
  1442. Require (TToken token, TToken rtkn)
  1443. {
  1444.     if (token != rtkn) {
  1445.         char msg[100], tknbuf[16];
  1446.  
  1447.         strcpy(tknbuf, TokenName(rtkn));
  1448.         sprintf(msg, "Expecting '%s', found '%s'", tknbuf, TokenName(token));
  1449.         ParseError(msg);
  1450.     }
  1451. }
  1452.  
  1453.  
  1454. // Compile a literal integer
  1455. static void
  1456. DoLitInteger (long n)
  1457. {
  1458.     if (n >= SHRT_MIN && n <= SHRT_MAX) {
  1459.         PutOpAndWord(opINT, n);
  1460.     } else {
  1461.         TLitPtr lit;
  1462.         CodeLiteral(AddLiteral(lit));
  1463.         set_integer(&lit->fValue, n);
  1464.     }
  1465. }
  1466.  
  1467.  
  1468. // Compile a literal string
  1469. static void
  1470. DoLitString (void)
  1471. {
  1472.     TLitPtr lit;
  1473.     int n = AddLiteral(lit);
  1474.     set_string(&lit->fValue, MakeString(gTokStr, gTokVal));
  1475.     CodeLiteral(n);
  1476. }
  1477.  
  1478.  
  1479. // Make a literal string
  1480. static int
  1481. MakeLitString (KStr str)
  1482. {
  1483.     TLitPtr lit;
  1484.     int n = AddLiteral(lit);
  1485.     set_string(&lit->fValue, MakeString(str));
  1486.     return n;
  1487. }
  1488.  
  1489.  
  1490. // Make a literal reference to a variable
  1491. static int
  1492. MakeLitVariable (Entry sym)
  1493. {
  1494. #if 0
  1495.     int i = 0;
  1496.     for (TLitPtr p = literals; p != nil; p = p->fNext) {
  1497.         if (p->fValue.fType == tVar && p->fValue.fVar == sym) {
  1498.             PrintErrF("Found variable %d ‘", n);
  1499.             Print(&stderr_iostream, true, &p->fValue);
  1500.             PrintErrF("’ at %d\r", i);
  1501.         }
  1502.         ++i;
  1503.     }
  1504. #endif
  1505.  
  1506.     int n = 0;
  1507.     for (TLitPtr lit = literals; lit != nil; ++n, lit = lit->fNext)
  1508.         if (lit->fValue.fType == tVar && lit->fValue.fVar == sym)
  1509.             return n;
  1510.     n = AddLiteral(lit);
  1511.     set_var(&lit->fValue, sym);
  1512.     return n;
  1513. }
  1514.  
  1515.  
  1516. // Find a variable
  1517. static void
  1518. FindVariable (KStr id, PVal* pv)
  1519. {    
  1520.     int n;
  1521.     if ((n = FindArg(id)) >= 0) {
  1522.         pv->fFn = CodeArgument;
  1523.         pv->fVal = n;
  1524.     } else if ((n = FindTemp(id)) >= 0) {
  1525.         pv->fFn = CodeTemporary;
  1526.         pv->fVal = n;
  1527.     } else if (isnil(&methodclass)
  1528.           || !FindClassVar(claddr(&methodclass), id, pv)) {
  1529.         pv->fFn = CodeVariable;
  1530.         pv->fVal = MakeLitVariable(AddEntry(&symbols, id, stSData));
  1531.     }
  1532. }
  1533.  
  1534.  
  1535. // Find a class member variable
  1536. static bool
  1537. FindClassVar (Class aClass, KStr name, PVal* pv)
  1538. {
  1539.     Entry entry;
  1540.     if ((entry = RFindMember(aClass, name)) == nil)
  1541.         return false;
  1542.     switch (entry->fType) {
  1543.     case stData:
  1544.         pv->fFn = CodeMember;
  1545.         pv->fVal = entry->fValue.fInt;
  1546.         break;
  1547.     case stSData:
  1548.         pv->fFn = CodeVariable;
  1549.            pv->fVal = MakeLitVariable(entry);
  1550.         break;
  1551.     case stFunction:
  1552.         FindVariable("this", pv);
  1553.         DoSend(name, pv);
  1554.         break;
  1555.     case stSFunction:
  1556.         CodeVariable(kLoad, MakeLitVariable(entry));
  1557.         pv->ClearFn();
  1558.         break;
  1559.     }
  1560.     return true;
  1561. }
  1562.  
  1563.  
  1564. // Compile an argument reference
  1565. static void
  1566. CodeArgument (int fcn, int n)
  1567. {
  1568.     switch (fcn) {
  1569.         case kLoad:        Put2CByte(opAREF, n); break;
  1570.         case kStore:    Put2CByte(opASET, n); break;
  1571.     }
  1572. }
  1573.  
  1574.  
  1575. // Compile a temporary variable reference
  1576. static void
  1577. CodeTemporary (int fcn, int n)
  1578. {
  1579.     switch (fcn) {
  1580.         case kLoad:        Put2CByte(opTREF, n); break;
  1581.         case kStore:    Put2CByte(opTSET, n); break;
  1582.     }
  1583. }
  1584.  
  1585.  
  1586. // Compile a data member reference
  1587. static void
  1588. CodeMember (int fcn, int n)
  1589. {
  1590.     switch (fcn) {
  1591.         case kLoad:        Put2CByte(opMREF, n); break;
  1592.         case kStore:    Put2CByte(opMSET, n); break;
  1593.     }
  1594. }
  1595.  
  1596.  
  1597. // Compile a variable reference
  1598. static void
  1599. CodeVariable (int fcn, int n)
  1600. {
  1601.     switch (fcn) {
  1602.         case kLoad:        Put2CByte(opREF, n); break;
  1603.         case kStore:    Put2CByte(opSET, n); break;
  1604.     }
  1605. }
  1606.  
  1607.  
  1608. // Compile an indexed reference
  1609. static void
  1610. CodeIndex (int fcn, int n)
  1611. {
  1612.     switch (fcn) {
  1613.         case kLoad:        PutCByte(opVREF);    break;
  1614.         case kStore:    PutCByte(opVSET);    break;
  1615.         case kPush:        PutCByte(opPUSH);    break;
  1616.         case kDup:        PutCByte(opDUP2);    break;
  1617.     }
  1618. }
  1619.  
  1620.  
  1621. // Compile a literal reference
  1622. static void
  1623. CodeLiteral (int n)
  1624. {
  1625.     Put2CByte(opLIT, n);
  1626. }
  1627.  
  1628.  
  1629. static void
  1630. NoCodeSpace (void)
  1631. {
  1632.     ParseError("Insufficient code space");
  1633. }
  1634.  
  1635.  
  1636. // Put a code byte into data space
  1637. static void
  1638. PutCByte (_Code b)
  1639. {
  1640.     _PutByte(b);
  1641.     _CheckCodeSpace();
  1642. }
  1643.  
  1644.  
  1645. // Put 2 bytes into data space
  1646. static void
  1647. Put2CByte (_Code a, _Code b)
  1648. {
  1649.     _PutByte(a);
  1650.     _PutByte(b);
  1651.     _CheckCodeSpace();
  1652. }
  1653.  
  1654.  
  1655. // Put an opcode and a 0 word into code space.  Return offset of 0 word
  1656. static _CWord
  1657. BranchForward (_Code op)
  1658. {
  1659.     _PutByte(op);
  1660.     _CWordAt(cptr) = 0;
  1661.     cptr += 2;
  1662.     _CheckCodeSpace();
  1663.     return cptr - 2;
  1664. }
  1665.  
  1666.  
  1667. // Put an opcode and a data word into code space.  Return offset of data word
  1668. static _CWord
  1669. PutOpAndWord (_Code op, CWord w)
  1670. {
  1671.     _PutByte(op);
  1672.     _CWordAt(cptr) = w;
  1673.     cptr += 2;
  1674.     _CheckCodeSpace();
  1675.     return cptr - 2;
  1676. }
  1677.  
  1678.  
  1679. // Fix up a reference chain
  1680. static void
  1681. FixUp (_CWord chain)
  1682. {
  1683.     for (_CWord next; chain; chain = next) {
  1684.         next = _CWordAt(chain);
  1685.         _CWordAt(chain) = cptr;
  1686.     }
  1687. }
  1688.  
  1689.  
  1690. // Make a copy of a string
  1691. static char*
  1692. copystring (KStr str)
  1693. {
  1694.     char* s = (char*) GetMemory(strlen(str) + 1);
  1695.     strcpy(s, str);
  1696.     return s;
  1697. }
  1698.  
  1699.  
  1700. #if qDebugMem
  1701. static int pMemCount = 0;
  1702. #endif
  1703.  
  1704.  
  1705. // Allocate memory and complain if there isn't enough
  1706. static void*
  1707. GetMemory (int size)
  1708. {
  1709.     size = (size + (sizeof(SInt32) - 1)) & ~(sizeof(SInt32) - 1);
  1710. #if qDebugMem
  1711.     if (Opt(Debug))
  1712.         PrintErrF("\t\tMem used = %d\r", pMemCount += size);
  1713. #endif
  1714.  
  1715.     void* ptr = pNextMem;
  1716.     pNextMem += size;
  1717.  
  1718.     if (pNextMem > &pTempMem[kMaxTempMem])
  1719.         Error("Insufficient memory");
  1720.     return ptr;
  1721. }
  1722.  
  1723.  
  1724. #if qDebugMem
  1725. static void
  1726. FreeAll (void)
  1727. {
  1728.     if (Opt(Debug)) {
  1729.         PrintErrF("\t\tTotal mem used = %d\r", pMemCount);
  1730.         pMemCount = 0;
  1731.     }
  1732.  
  1733.     pNextMem = pTempMem;
  1734. }
  1735. #endif
  1736.